package com.loong.news.handler;

import com.loong.common.constant.NewsOperationType;
import com.loong.common.domain.Pager;
import com.loong.common.enumerate.ResultCode;
import com.loong.common.exception.GlobalException;
import com.loong.common.redis.RedisTools;
import com.loong.common.utils.TransformUtils;
import com.loong.global.constant.RedisKey;
import com.loong.news.business.NewsBusiness;
import com.loong.common.constant.NewsStatus;
import com.loong.news.common.backend.param.BatchOperationNewsParam;
import com.loong.news.common.backend.param.NewsListQueryParam;
import com.loong.news.common.backend.param.NewsParam;
import com.loong.news.common.backend.result.NewsResult;
import com.loong.news.mapper.NewsMapper;
import com.loong.news.param.NewsListParam;
import com.loong.news.model.News;
import org.apache.commons.lang.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;

/**
 * @Description: 操作新闻的handler
 * @Author: 刘群
 * @Date: 2020/10/14 17:39
 */
@Service
public class NewsHandler  {

    @Resource
    private NewsBusiness newsBusiness;

    @Resource
    private NewsMapper newsMapper;

    @Resource
    private NewsOperationRecordHandler recordHandler;


    /**
     * 分页查询普通新闻列表：结果显示给后台管理
     * @param param
     * @return
     */
    public Pager<NewsResult> newsListPageQuery(NewsListQueryParam param){
        Pager<News> pager = newsBusiness.pageQuery(param, () -> newsMapper.findNewsList(TransformUtils.transform(param,NewsListParam.class)));
        return TransformUtils.transformPage(pager,NewsResult.class);
    }

    /**
     * 分页查询历史新闻列表：结果显示给后台管理
     * @param param
     * @return
     */
    public Pager<NewsResult> historyNewsPageQuery(NewsListQueryParam param){
        Pager<News> pager = newsBusiness.pageQuery(param, () -> newsMapper.findHistoryNews(TransformUtils.transform(param,NewsListParam.class)));
        return TransformUtils.transformPage(pager, NewsResult.class);
    }

    /**
     * 分页查询已发布的新闻，并将结果展示给前台
     * @param param
     * @return
     */
    public Pager<NewsResult> newsListToForeheadPageQuery(NewsListQueryParam param){
        Pager<News> pager = newsBusiness.pageQuery(param, () -> newsMapper.findNewsListToForehead(TransformUtils.transform(param,NewsListParam.class)));
        return TransformUtils.transformPage(pager,NewsResult.class);
    }

    /**
     * 获得每条新闻的图片和视频数量
     * @param picturePath
     * @param videoPath
     * @return
     */
    private Integer getNewsImageAndVideoNums(String picturePath,String videoPath){
        Integer pictureNum = 0;
        Integer  videoNum = 0;
        if (StringUtils.isNotEmpty(picturePath)){
            //获得图片的数量
            pictureNum = picturePath.split(",").length;
        }
        if (StringUtils.isNotEmpty(videoPath)){
            //获得视频的数量
            videoNum = videoPath.split(",").length;
        }
        return pictureNum+videoNum;
    }

    /**
     * 编辑并批准发布新闻：
     * @param param
     */
    @Transactional
    public void editAndApproveNews(NewsParam param) {
        this.editAndOperationNews(NewsStatus.RELEASED,NewsOperationType.APPROVE,param);
    }
    /**
     * 编辑并驳回新闻：
     * @param param
     */
    @Transactional
    public void editAndRejectNews(NewsParam param) {
        this.editAndOperationNews(NewsStatus.REJECTED,NewsOperationType.REJECT,param);
    }
    /**
     * 编辑并发布新闻：
     * @param param
     */
    @Transactional
    public void editAndReleaseNews(NewsParam param) {
        this.editAndOperationNews(NewsStatus.RELEASED,NewsOperationType.RELEASE,param);
    }
    /**
     * 编辑新闻之后，直接下架新闻：
     * @param param
     */
    @Transactional
    public void editAndRemoveNews(NewsParam param) {
        this.editAndOperationNews(NewsStatus.UNRELEASED,NewsOperationType.REMOVE,param);
    }
    /**
     * 编辑新闻后直接保存：
     * @param param
     */
    @Transactional
    public void editAndSaveNews(NewsParam param) {
        this.editAndOperationNews(null,NewsOperationType.EDIT,param);
    }

    /**
     * 编辑新闻之后对应的相应操作：approve、remove、release、save、reject操作
     * @param newsStatus 新闻状态
     * @param newsOperationType 新闻操作类型
     * @param param 新闻参数
     */
    @Transactional
    public void editAndOperationNews(Integer newsStatus,String newsOperationType,NewsParam param){
        param.setLastUpdateTime(new Date());
        //设置新闻的图片和视频的总数量
        Integer num = this.getNewsImageAndVideoNums(param.getPicturePath(), param.getVideoPath());
        param.setImageAndVideoNum(num);
        //设置新闻的状态
        if (null != newsStatus){
            param.setStatus(newsStatus);
        }
        if ("approve".equals(newsOperationType)||"release".equals(newsOperationType)){
            if (ObjectUtils.isEmpty(param.getReleaseTime())){
                //若后台管理没将新闻发布时间发送过来，则设置发布时间
                param.setReleaseTime(param.getLastUpdateTime());
            }
            //新增批准或者发布新闻操作记录到数据库：
            recordHandler.saveNewsOperationRecord(param.getAccount(),newsOperationType,param.getLastUpdateTime(),param.getId());
        }
        if ("reject".equals(newsOperationType)){
            if (ObjectUtils.isEmpty(param.getRejectTime())){
                //若后台没将新闻驳回时间发送过来，则设置驳回时间
                param.setRejectTime(param.getLastUpdateTime());
            }
            //新增驳回新闻操作记录到数据库：
            recordHandler.saveNewsOperationRecord(param.getAccount(),newsOperationType,param.getLastUpdateTime(),param.getId());
        }
        if ("remove".equals(newsOperationType)){
            param.setTop(false);//设置top值为0即该新闻不置顶
            //新增下架新闻操作记录到数据库：
            recordHandler.saveNewsOperationRecord(param.getAccount(),newsOperationType,param.getLastUpdateTime(),param.getId());
        }
        //更新数据库中的新闻：
        newsBusiness.updateByPrimaryKeySelective(TransformUtils.transform(param, News.class));
        //新增编辑新闻操作记录到数据库：
        recordHandler.saveNewsOperationRecord(param.getAccount(), NewsOperationType.EDIT,param.getLastUpdateTime(),param.getId());
    }

    /**
     * 根据新闻id查询新闻
     * @param newsId
     * @return
     */
    public NewsResult findNewsById(Long newsId){
        //查询该条新闻的所有内容
        News news = newsBusiness.findById(newsId);
        if (ObjectUtils.isEmpty(news)) return null;
        return TransformUtils.transform(news,NewsResult.class);
    }

    /**
     * 批量通过新闻的审核
     * @param param
     */
    @Transactional
    public void batchApprovalNews(BatchOperationNewsParam param){
        this.batchOperationNews(NewsStatus.RELEASED,NewsOperationType.APPROVE,param);
    }
    /**
     * 批量驳回新闻的审核
     * @param param
     */
    @Transactional
    public void batchRejectNews(BatchOperationNewsParam param){
        this.batchOperationNews(NewsStatus.REJECTED,NewsOperationType.REJECT,param);
    }
    /**
     * 批量撤销置顶新闻
     * @param param
     */
    @Transactional
    public void batchRevokeNews(BatchOperationNewsParam param){
        this.batchOperationNews(null,NewsOperationType.REVOKE,param);
    }
    /**
     * 批量下架新闻
     * @param param
     */
    @Transactional
    public void batchRemoveNews(BatchOperationNewsParam param){
        this.batchOperationNews(NewsStatus.UNRELEASED,NewsOperationType.REMOVE,param);
    }

    /**
     * 批量重新通过新闻
     * @param param
     */
    @Transactional
    public void batchReApproveNews(BatchOperationNewsParam param){
        this.batchOperationNews(NewsStatus.RELEASED,NewsOperationType.RE_APPROVE,param);
    }
    /**
     * 批量发布新闻
     * @param param
     */
    @Transactional
    public void batchReleaseNews(BatchOperationNewsParam param){
        this.batchOperationNews(NewsStatus.RELEASED,NewsOperationType.RELEASE,param);
    }

    /**
     * 批量操作新闻：batchApproval、batchReject、batchRevoke、batchRemove、batchReApprove、batchRelease
     * @param newsStatus 新闻状态
     * @param newsOperationType 新闻操作类型
     * @param param
     */
    @Transactional
    public void batchOperationNews(Integer newsStatus, String newsOperationType, BatchOperationNewsParam param) {
        String[] idList = param.getIds().split(",");
        for (String id : idList) {
            NewsParam newsParam = NewsParam.builder()
                    .id(Long.valueOf(id))
                    .lastUpdateTime(new Date())
                    .build(); //要更新的新闻参数
            if (null != newsStatus){
                newsParam.setStatus(newsStatus);
            }
            if ("approve".equals(newsOperationType)||"release".equals(newsOperationType)||"re_approve".equals(newsOperationType)) {
                newsParam.setReleaseTime(param.getOperationTime());//设置新闻发布时间
            }
            if ("reject".equals(newsOperationType)) {
                newsParam.setRejectTime(param.getOperationTime());//设置新闻的驳回时间
            }
            if ("revoke".equals(newsOperationType) || "remove".equals(newsOperationType)){
                //直接点击撤销新闻或者下架新闻都需要将置顶top值该为0
                newsParam.setTop(false);
            }
            //更新新闻状态
            newsBusiness.updateByPrimaryKeySelective(TransformUtils.transform(newsParam, News.class));
            //新增新闻的操作记录：
            recordHandler.saveNewsOperationRecord(param.getAccount(), newsOperationType, param.getOperationTime(), Long.valueOf(id));
        }
    }

    /**
     * 批量置顶新闻
     * @param param
     * @return
     */
    @Transactional
    public void batchTopNews(BatchOperationNewsParam param){
        String[] idList = param.getIds().split(",");
        for (String id : idList) {
            //根据新闻id查询出该新闻的类型：
            Long categoryId = newsMapper.findCategoryIdByNewsId(Long.valueOf(id));
            //根据新闻类别id查询出该类别的新闻置顶的总数：
            Integer topNum = newsMapper.findTopNumByCategoryId(categoryId);
            if (topNum < 3){
                //置顶新闻：top值为1表示置顶
                NewsParam newsParam = NewsParam.builder()
                        .top(true)
                        .id(Long.valueOf(id))
                        .lastUpdateTime(new Date())
                        .build();
                newsBusiness.updateByPrimaryKeySelective(TransformUtils.transform(newsParam,News.class));
                //新增置顶新闻的操作记录：
                recordHandler.saveNewsOperationRecord(param.getAccount(),NewsOperationType.TOP,param.getOperationTime(),Long.valueOf(id));
            }else{
                throw new GlobalException(ResultCode.PARAM_ERROR,"Only three news in each category can be placed at the top");
            }
        }
    }

    /**
     * 批量删除新闻
     * @param idList
     */
    @Transactional
    public void batchDeleteNews(List<Long> idList){
        //批量删除关于对应新闻的操作记录：
        recordHandler.deleteRecordsByNewsId(idList);
        //批量删除新闻：
        newsBusiness.deleteByIds(StringUtils.join(idList,","));
    }

    /**
     * 新增并保存新闻
     * @param param
     */
    @Transactional
    public void createAndSaveNews(NewsParam param) {
        this.createAndOperationNews(NewsStatus.UNRELEASED,NewsOperationType.CREATE,param);
    }
    /**
     * 新增并发布新闻
     * @param param
     */
    @Transactional
    public void createAndReleaseNews(NewsParam param) {
        this.createAndOperationNews(NewsStatus.RELEASED,NewsOperationType.RELEASE,param);
    }

    /**
     * 创建新闻之后的操作：createAndSaveNews、createAndReleaseNews
     * @param newsStatus 新闻状态
     * @param newsOperationType 新闻操作类型
     * @param param
     */
    @Transactional
    public void createAndOperationNews(Integer newsStatus,String newsOperationType,NewsParam param){
        param.setCreateTime(new Date());
        //设置新闻的图片和视频总数：
        Integer num = this.getNewsImageAndVideoNums(param.getPicturePath(), param.getVideoPath());
        param.setImageAndVideoNum(num);
        //设置新闻的状态：
        param.setStatus(newsStatus);
        if ("release".equals(newsOperationType)){
            param.setReleaseTime(param.getCreateTime());//设置新闻的发布时间
        }
        News news = TransformUtils.transform(param, News.class);
        //保存新闻到数据库中：
        newsBusiness.save(news);
        if ("release".equals(newsOperationType)){
            //新增发布新闻的操作记录：这里必须是news.getId()，因为获得的是新增新闻之后该新闻的主键id
            recordHandler.saveNewsOperationRecord(param.getAccount(),newsOperationType,param.getCreateTime(),news.getId());
        }
        //新增创建新闻的操作记录：这里必须是news.getId()，因为获得的是新增新闻之后该新闻的主键id
        recordHandler.saveNewsOperationRecord(param.getAccount(),NewsOperationType.CREATE,param.getCreateTime(),news.getId());
    }

    /**
     * 阅读新闻时将Redis中存放的阅读数+1
     * @param newsId
     * @return
     */
    public NewsResult readNews(Long newsId){
        //阅读数+1：
        RedisTools.valueOperations().increment(RedisKey.NEWS.NEWS_ID+newsId+RedisKey.NEWS.READ_NUM);
        return this.findNewsById(newsId);//查询出该新闻返回给前台
    }
    /**
     * 分享新闻时将Redis中存放的该分享数+1
     * @param newsId
     */
    public void shareNews(Long newsId){
        //分享数+1：
        RedisTools.valueOperations().increment(RedisKey.NEWS.NEWS_ID+newsId+RedisKey.NEWS.SHARE_NUM);
    }

    /**
     * 点赞新闻时将Redis中存放的该点赞数+1
     * @param newsId
     */
    public void likeNews(Long newsId){
        //点赞数+1：
        RedisTools.valueOperations().increment(RedisKey.NEWS.NEWS_ID+newsId+RedisKey.NEWS.LIKE_NUM);
    }

    /**
     * 举报新闻时将Redis中存放的该举报数+1
     * @param newsId
     */
    public void unLikeNews(Long newsId){
        //举报数+1：
        RedisTools.valueOperations().increment(RedisKey.NEWS.NEWS_ID+newsId+RedisKey.NEWS.UNLIKE_NUM);
    }

    /**
     * 从Redis中获取新闻的阅读数、分享数、点赞数、举报数，并更新到数据库中
     * @param newsId
     */
    public void updateNewsNumFields(Long newsId){
        //从Redis中获取readNum、shareNum、likeNum、unLikeNum
        Integer readNum = (Integer) RedisTools.valueOperations().get(RedisKey.NEWS.NEWS_ID+newsId+RedisKey.NEWS.READ_NUM);
        Integer shareNum = (Integer) RedisTools.valueOperations().get(RedisKey.NEWS.NEWS_ID+newsId+RedisKey.NEWS.SHARE_NUM);
        Integer likeNum = (Integer) RedisTools.valueOperations().get(RedisKey.NEWS.NEWS_ID+newsId+RedisKey.NEWS.LIKE_NUM);
        Integer unLikeNum = (Integer) RedisTools.valueOperations().get(RedisKey.NEWS.NEWS_ID+newsId+RedisKey.NEWS.UNLIKE_NUM);

        if (readNum == null) readNum = 0;
        if (shareNum == null) shareNum = 0;
        if (likeNum == null) likeNum = 0;
        if (unLikeNum == null) unLikeNum = 0;

        NewsParam newsParam = NewsParam.builder()
                .id(newsId)
                .readNum(readNum.longValue())
                .shareNum(shareNum.longValue())
                .likeNum(likeNum.longValue())
                .unlikeNum(unLikeNum.longValue())
                .lastUpdateTime(new Date())
                .build();
        newsBusiness.updateByPrimaryKeySelective(TransformUtils.transform(newsParam,News.class));
    }

    /**
     * 查询新闻来源
     * @return 新闻来源的集合
     */
    public List<String> findPress(){
        return newsMapper.findPress();
    }

    /**
     * 拉取新闻
     */
    public void pullNews(){

    }
}
